home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1997 April / EnigmA AMIGA RUN 17 (1997)(G.R. Edizioni)(IT)[!][issue 1997-04][EAR-CD].iso / EARCD / text / hyper / hsc_source.lha / hsc / source / hsctools / hscpitt.c < prev    next >
C/C++ Source or Header  |  1996-11-24  |  19KB  |  798 lines

  1. /*
  2.  * hscpitt
  3.  *
  4.  * hsc project interfering'n'trashing tool
  5.  *
  6.  * Copyright (C) 1996  Thomas Aglassinger
  7.  *
  8.  * This program is free software; you can redistribute it and/or modify
  9.  * it under the terms of the GNU General Public License as published by
  10.  * the Free Software Foundation; either version 2 of the License, or
  11.  * (at your option) any later version.
  12.  *
  13.  * This program is distributed in the hope that it will be useful,
  14.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.  * GNU General Public License for more details.
  17.  *
  18.  * You should have received a copy of the GNU General Public License
  19.  * along with this program; if not, write to the Free Software
  20.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21.  *
  22.  *-------------------------------------------------------------------
  23.  *
  24.  * Author : Thomas Aglassinger (Tommy-Saftwörx)
  25.  * Email  : agi@giga.or.at, agi@sbox.tu-graz.ac.at
  26.  * Address: Lissagasse 12/II/9
  27.  *          8020 Graz
  28.  *          AUSTRIA
  29.  *
  30.  *-------------------------------------------------------------------
  31.  *
  32.  * hsctools/hscpitt.c
  33.  *
  34.  * updated: 24-Nov-1996
  35.  * created: 15-Oct-1996
  36.  */
  37.  
  38. /* ANSI includes */
  39. #include <stdio.h>
  40. #include <errno.h>
  41. #include <string.h>
  42. #include <time.h>
  43.  
  44. /* include revision data */
  45. #include "hsctools/pitt_rev.h"
  46.  
  47. /* ugly includes */
  48. #include "ugly/ustring.h"
  49. #include "ugly/dllist.h"
  50. #include "ugly/expstr.h"
  51. #include "ugly/infile.h"
  52. #include "ugly/uargs.h"
  53. #include "ugly/ustrlist.h"
  54. #include "ugly/prginfo.h"
  55. #include "ugly/returncd.h"
  56.  
  57. /* hsclib includes */
  58. #include "hscprj/document.h"
  59. #include "hscprj/project.h"
  60. #include "hscprj/license.h"
  61.  
  62. #ifdef AMIGA
  63. /* AmigaOS version string
  64.  * (imported from "pitt_rev.h")
  65.  */
  66. static const STRPTR AmigaOS_version = VERSTAG;
  67. #endif
  68.  
  69. /* prefix for messages */
  70. #define HP ""
  71. #define DHP "*hscpit* "
  72. #define SHIT "*** "             /* prefix for total failure */
  73.  
  74. /* debugging define */
  75. #ifdef DEBUG
  76. #undef DEBUG
  77. #define DEBUG 1
  78. #endif
  79.  
  80. #ifdef D
  81. #undef D
  82. #endif
  83.  
  84. #if DEBUG
  85. #define D(x) if (debug) {x;}
  86. #else
  87. #define D(x) {/*nufin*/}
  88. #endif
  89.  
  90. /* default parameters */
  91. #define DEFAULT_PROJECT "hsc.project"   /* project-filename */
  92.  
  93. /* commands supported */
  94. #define CMD_COUNT_STR   "count"
  95. #define CMD_LIST_STR    "list"
  96. #define CMD_EXTRACT_STR "extract"
  97. #define CMD_DELETE_STR  "delete"
  98. #define CMD_ERASE_STR   "erase"
  99. #define CMD_RENAME_STR  "rename"
  100. #define CMD_COPY_STR    "copy"
  101.  
  102. #define COMMAND_NONE    0
  103. #define COMMAND_COUNT   1
  104. #define COMMAND_LIST    2
  105. #define COMMAND_EXTRACT 3
  106. #define COMMAND_DELETE  4
  107. #define COMMAND_ERASE   5
  108. #define COMMAND_RENAME  6
  109. #define COMMAND_COPY    7
  110.  
  111. #define COMMAND_ENUMSTR     \
  112.         CMD_COUNT_STR    "|" \
  113.         CMD_LIST_STR    "|" \
  114.         CMD_EXTRACT_STR "|" \
  115.         CMD_DELETE_STR  "|" \
  116.         CMD_ERASE_STR
  117.  
  118. /*
  119.  * global vars
  120.  */
  121. static int return_code = RC_FAIL;       /* exit code of program */
  122.  
  123. static STRPTR prjfile = NULL;
  124. static LONG command = COMMAND_LIST;
  125. static LONG cmdArgNum = 0;      /* number of args for command (ARG/M) */
  126. static DLLIST *command_arglist = NULL;
  127. static BOOL quiet = FALSE;
  128. static BOOL debug = FALSE;
  129. static BOOL arg_help = FALSE;
  130. static BOOL arg_license = FALSE;
  131.  
  132. static HSCPRJ *project = NULL;
  133.  
  134. /* command strings */
  135. static STRPTR command_name[] =
  136. {
  137.     "***NONE***",
  138.     CMD_COUNT_STR,
  139.     CMD_LIST_STR,
  140.     CMD_EXTRACT_STR,
  141.     CMD_DELETE_STR,
  142.     CMD_RENAME_STR,
  143.     CMD_COPY_STR,
  144.     NULL
  145. };
  146.  
  147. /*
  148.  * cleanup: free all resources
  149.  * (called in any case)
  150.  */
  151. static VOID cleanup(VOID)
  152. {
  153.     D(fprintf(stderr, "(cleanup)\r"));
  154.     del_dllist(command_arglist);
  155.     del_project(project);
  156.     D(fprintf(stderr, "         \r"));
  157. }
  158.  
  159. static VOID set_return_code(int new_code)
  160. {
  161.     if (new_code > return_code)
  162.         return_code = new_code;
  163. }
  164.  
  165. /*
  166.  * hsc_nomem_handler
  167.  *
  168.  * called from ugly/umalloc, if malloc() did return NULL
  169.  */
  170. static BOOL hscpitt_nomem_handler(size_t size)
  171. {
  172.     fputs(SHIT "out of memory\n", stderr);
  173.  
  174.     return_code = RC_FAIL;
  175.  
  176.     exit(return_code);
  177.  
  178.     return (FALSE);             /* immediatly abort */
  179. }
  180.  
  181. VOID msg_corrupt_pf(HSCPRJ * hp, STRPTR reason)
  182. {
  183.     fprintf(stderr, "project-file corrupt: %s\n", reason);
  184.     set_return_code(RC_ERROR);
  185. }
  186.  
  187. /*
  188.  * update_project_file
  189.  *
  190.  * write updated project file, handle errors
  191.  */
  192. BOOL update_project_file(HSCPRJ * project)
  193. {
  194.     BOOL ok = FALSE;
  195.  
  196.     D(fprintf(stderr, DHP "update_project_file()\n"));
  197.     /* TODO: create backup */
  198.     ok = hsc_project_write_file(project, prjfile);
  199.  
  200.     if (!ok)
  201.     {
  202.         fprintf(stderr, "error writing project file\n");        /* TODO: be more specific */
  203.         set_return_code(RC_ERROR);
  204.     }
  205.  
  206.     return (ok);
  207. }
  208.  
  209. /*-------------------------------------------------------------------
  210.  *
  211.  * functions for arguments
  212.  *
  213.  *-------------------------------------------------------------------*/
  214.  
  215. /*
  216.  * check_min_cmd_args
  217.  *
  218.  * check, if at least a specific num of args has been specified
  219.  * for the command
  220.  */
  221. BOOL check_min_cmd_args(LONG minArgNum, DLLIST * list)
  222. {
  223.     BOOL ok = TRUE;
  224.     DLNODE *nd = dll_first(list);
  225.     LONG argNum = 0;
  226.  
  227.     /* count arguments */
  228.     while (nd)
  229.     {
  230.         argNum++;
  231.         nd = dln_next(nd);
  232.     }
  233.  
  234.     if (argNum < minArgNum)
  235.     {
  236.         fprintf(stderr, "command %s requires at least %ld arguments\n",
  237.                 command_name[command], minArgNum);
  238.         ok = FALSE;
  239.     }
  240.  
  241.     return (ok);
  242. }
  243.  
  244. /*
  245.  * args_ok
  246.  *
  247.  * prepare args, check & parse user args, display error and
  248.  * help message if neccessary
  249.  *
  250.  * result: TRUE, if all args ok and no request for HELP or
  251.  *         LICENSE has been detected
  252.  */
  253. static BOOL args_ok(int argc, char *argv[])
  254. {
  255.     struct arglist *hscpitt_args;       /* argument structure */
  256.     BOOL arg_help = FALSE;
  257.     BOOL arg_license = FALSE;
  258.     BOOL ok = FALSE;
  259.  
  260.     /* create arg-table */
  261.     hscpitt_args = prepare_args
  262.         ("HSCPITT_ARGS",
  263.          "COMMAND/E", COMMAND_ENUMSTR, &command,
  264.          "command to perform (" COMMAND_ENUMSTR ")",
  265.          "ARG/T/M", &command_arglist, "command argument(s)",
  266.          "PRJFILE/T/K", &prjfile, "project file",
  267.          "QUIET/S", &quiet, "act quietly",
  268.          "-DEBUG/S", &debug, "enable debugging output",
  269.          "HELP=?=-h/S", &arg_help, "display this text",
  270.          "LICENSE/S", &arg_license, "display license",
  271.          NULL);
  272.  
  273.     ok = (hscpitt_args != NULL);
  274.  
  275.     /* set & test args */
  276.     if (ok)
  277.     {
  278.         ok = set_args(argc, argv, hscpitt_args);
  279.  
  280.         /* display argument error message */
  281.         if (!ok)
  282.         {
  283.             pargerr();
  284.             set_return_code(RC_ERROR);
  285.         }
  286.         else if (arg_help || arg_license)
  287.         {
  288.             /*
  289.              * display help or license text
  290.              */
  291.             fprintf_prginfo(stderr);
  292.             if (arg_help)
  293.                 fprintf_arghelp(stderr, hscpitt_args);
  294.             else
  295.                 show_license();
  296.             set_return_code(RC_WARN);
  297.             ok = FALSE;
  298.         }
  299.         else
  300.         {
  301.             /* display copyright in verbose-mode */
  302.             if (!quiet)
  303.                 fprintf_prginfo(stderr);
  304.  
  305.             /* set default-parameters if neccessary */
  306.             if (!prjfile)
  307.             {
  308.                 prjfile = DEFAULT_PROJECT;
  309.                 if (!quiet)
  310.                 {
  311.                     fprintf(stderr, HP "%s: using default project-file\n",
  312.                             prjfile);
  313.                 }
  314.             }
  315.  
  316.             if (command)
  317.             {
  318.                 /* debugging control output */
  319.                 D(
  320.                      {
  321.                      fprintf(stderr, DHP "prjfile =`%s'\n", prjfile);
  322.                      fprintf(stderr, DHP "command =`%ld'\n", command);
  323.                      }
  324.                 );
  325.             }
  326.             else
  327.             {
  328.                 fprintf(stderr, "no command specified\n");
  329.                 ok = FALSE;
  330.             }
  331.         }
  332.  
  333.         /* set error return code if neccessary */
  334.         if (!ok)
  335.         {
  336.             set_return_code(RC_ERROR);
  337.         }
  338.  
  339.         /* release mem used by args */
  340.         free_args(hscpitt_args);
  341.     }
  342.     else
  343.     {
  344.         /* only for developer */
  345.         D(fprintf(stderr, SHIT "ArgDef error: %lu\n", prep_error_num));
  346.     }
  347.  
  348. #if 1
  349.     return (ok);
  350. #else
  351.     return (FALSE);             /* for arg-debugging */
  352. #endif
  353. }
  354.  
  355. /*
  356.  * read_project
  357.  *
  358.  * read data from project file
  359.  */
  360. static BOOL read_project(VOID)
  361. {
  362.     BOOL ok = FALSE;
  363.     INFILE *inpf = NULL;
  364.  
  365.     if (!quiet)
  366.     {
  367.         fprintf(stderr, HP "%s: reading..\r", prjfile);
  368.         fflush(stderr);
  369.     }
  370.  
  371.     /* assign message-callback for corrupt project-file */
  372.     project->CB_msg_corrupt_pf = msg_corrupt_pf;
  373.  
  374.     /* read project-file */
  375.     errno = 0;
  376.     inpf = infopen(prjfile, 1024);
  377.     if (inpf)
  378.     {
  379.         if (hsc_project_read_file(project, inpf))
  380.         {
  381.             if (!quiet)
  382.             {
  383.                 fprintf(stderr, HP "%s: project-file read\n", prjfile);
  384.             }
  385.             ok = TRUE;
  386.         }
  387.         infclose(inpf);
  388.     }
  389.  
  390.     if (!ok)
  391.     {
  392.         fprintf(stderr, HP "error reading `%s'", prjfile);
  393.         if (errno)
  394.             fprintf(stderr, HP ": %s", strerror(errno));
  395.         fprintf(stderr, "\n");
  396.     }
  397.  
  398.     return (ok);
  399. }
  400.  
  401. /*-------------------------------------------------------------------
  402.  *
  403.  * functions for commands arguments
  404.  *
  405.  *-------------------------------------------------------------------*/
  406.  
  407. /* check for no args */
  408. static BOOL chkArg0(STRPTR command)
  409. {
  410.     BOOL ok = TRUE;
  411.     if (cmdArgNum)
  412.     {
  413.         printf("no arguments allowed to command `%s'\n", command);
  414.         ok = FALSE;
  415.     }
  416.     return (ok);
  417. }
  418.  
  419. /* check for at least one arg (or more) */
  420. static BOOL chkArgAny(STRPTR command)
  421. {
  422.     BOOL ok = TRUE;
  423.     if (!cmdArgNum)
  424.     {
  425.         printf("arguments required for command `%s'\n", command);
  426.         ok = FALSE;
  427.     }
  428.     return (ok);
  429. }
  430.  
  431. /*-------------------------------------------------------------------
  432.  *
  433.  * functions for commands
  434.  *
  435.  *-------------------------------------------------------------------*/
  436.  
  437. /*
  438.  * command_delete
  439.  *
  440.  * remove document(s) from project
  441.  */
  442. VOID command_delete(HSCPRJ * project, DLLIST * arglist)
  443. {
  444.     if (chkArgAny(CMD_DELETE_STR))
  445.     {
  446.         DLNODE *docNode = dll_first(arglist);
  447.  
  448.         while (docNode)
  449.         {
  450.             STRPTR docName = (STRPTR) dln_data(docNode);
  451.             BOOL deleted = FALSE;
  452.  
  453.             /* remove document */
  454.             deleted = hsc_project_del_document(project, docName);
  455.  
  456.             /* output message */
  457.             if (deleted)
  458.             {
  459.                 if (!quiet)
  460.                 {
  461.                     printf("Delete `%s'\n", docName);
  462.                 }
  463.             }
  464.             else
  465.             {
  466.                 printf("Delete `%s': no such document\n", docName);
  467.                 set_return_code(RC_WARN);
  468.             }
  469.             docNode = dln_next(docNode);
  470.         }
  471.  
  472.         /* update project file */
  473.         update_project_file(project);
  474.     }
  475. }
  476.  
  477. /*-------------------------------------------------------------------*/
  478.  
  479. /*
  480.  * command_erase
  481.  *
  482.  * remove document(s) and corresponding files from project
  483.  */
  484. static BOOL uremove(STRPTR fname)
  485. {
  486.     BOOL erased = FALSE;
  487.  
  488.     /* TODO: convert URI to filename */
  489.     errno = 0;
  490.     erased = !remove(fname);
  491.     if (erased)
  492.     {
  493.         if (!quiet)
  494.         {
  495.             printf("Delete `%s'\n", fname);
  496.         }
  497.     }
  498.     else
  499.     {
  500.         printf("Error deleting `%s': %s\n", fname, strerror(errno));
  501.     }
  502.  
  503.     return (erased);
  504. }
  505.  
  506. VOID command_erase(HSCPRJ * project, DLLIST * arglist)
  507. {
  508.     if (chkArgAny(CMD_ERASE_STR))
  509.     {
  510.         DLNODE *argNode = dll_first(arglist);
  511.         BOOL erasedAny = FALSE;
  512.  
  513.         while (argNode)
  514.         {
  515.             STRPTR docName = (STRPTR) dln_data(argNode);
  516.             HSCDOC *document = find_document(project->documents, docName);
  517.             BOOL erased = FALSE;
  518.  
  519.             /* remove document and source file */
  520.             if (document)
  521.             {
  522.                 uremove(document->docname);
  523.                 uremove(document->sourcename);
  524.                 erased = hsc_project_del_document(project, docName);
  525.                 if (!erased)
  526.                     panic("no document entry");
  527.             }
  528.  
  529.             /* output message */
  530.             if (!erased)
  531.             {
  532.                 printf("Delete `%s': no such document\n", docName);
  533.                 set_return_code(RC_WARN);
  534.             }
  535.             else
  536.             {
  537.                 /* project file needs to be updated */
  538.                 erasedAny = TRUE;
  539.             }
  540.  
  541.             argNode = dln_next(argNode);
  542.         }
  543.  
  544.         /* update project file */
  545.         if (erasedAny)
  546.         {
  547.             update_project_file(project);
  548.         }
  549.     }
  550. }
  551.  
  552. /*-------------------------------------------------------------------*/
  553.  
  554. /*
  555.  * command_extract
  556.  *
  557.  * display detailed information about documents found in project
  558.  */
  559. static VOID printfVar(STRPTR var, STRPTR value)
  560. {
  561.     if (!value)
  562.         value = "";
  563.     printf("%s=\"%s\"\n", var, value);
  564. }
  565.  
  566. static VOID extractDocument(HSCPRJ * project, HSCDOC * document, BOOL emptyLine)
  567. {
  568.     /* show empty line; not for first document */
  569.     if (emptyLine)
  570.     {
  571.         puts("");
  572.     }
  573.  
  574.     /* display document name and source used */
  575.     printfVar("DOCUMENT", document->docname);
  576.     printfVar("SOURCE", document->sourcename);
  577.  
  578. #if 0
  579.     /* display includes */
  580.     if (document->includes)
  581.     {
  582.         DLNODE *nd = dll_first(document->includes);
  583.         while (nd)
  584.         {
  585.             HSCINC *include = (HSCINC *) dln_data(nd);
  586.             printfVar("INCLUDE", include->name);
  587.             nd = dln_next(nd);
  588.         }
  589.     }
  590. #endif
  591. }
  592.  
  593. VOID command_extract(HSCPRJ * project, DLLIST * arglist)
  594. {
  595.     if (cmdArgNum)
  596.     {
  597.         /* extract document(s) specified in args */
  598.         DLNODE *argNode = dll_first(arglist);
  599.         BOOL emptyLine = FALSE;
  600.  
  601.         while (argNode)
  602.         {
  603.             STRPTR docName = (STRPTR) dln_data(argNode);
  604.             HSCDOC *document = find_document(project->documents, docName);
  605.  
  606.             /* remove document and source file */
  607.             if (document)
  608.             {
  609.                 extractDocument(project, document, emptyLine);
  610.                 emptyLine = TRUE;
  611.             }
  612.             else
  613.             {
  614.                 fprintf(stderr, "Extract `%s': no such document\n", docName);
  615.                 set_return_code(RC_WARN);
  616.             }
  617.  
  618.             argNode = dln_next(argNode);
  619.         }
  620.     }
  621.     else
  622.     {
  623.         /* extract all documents */
  624.         DLNODE *docNode = dll_first(project->documents);
  625.         BOOL emptyLine = FALSE;
  626.  
  627.         while (docNode)
  628.         {
  629.             HSCDOC *document = (HSCDOC *) dln_data(docNode);
  630.  
  631.             extractDocument(project, document, emptyLine);
  632.             emptyLine = TRUE;
  633.  
  634.             /* process next node, show empty line if
  635.              * further data exist */
  636.             docNode = dln_next(docNode);
  637.         }
  638.     }
  639. }
  640.  
  641. /*-------------------------------------------------------------------*/
  642.  
  643. /*
  644.  * command_count
  645.  *
  646.  * display number of documents currently stored in project file
  647.  */
  648. VOID command_count(HSCPRJ * project, DLLIST * arglist)
  649. {
  650.     DLNODE *docNode = dll_first(project->documents);
  651.     ULONG docNum = 0;
  652.  
  653.     if (chkArg0(CMD_COUNT_STR))
  654.     {
  655.         while (docNode)
  656.         {
  657.             docNum++;
  658.             docNode = dln_next(docNode);
  659.         }
  660.  
  661.         /* display number of documents */
  662.         printf("%lu\n", docNum);
  663.     }
  664. }
  665.  
  666. /*-------------------------------------------------------------------*/
  667.  
  668. /*
  669.  * command_list
  670.  *
  671.  * display list of documents found in project
  672.  */
  673. VOID command_list(HSCPRJ * project, DLLIST * arglist)
  674. {
  675.     if (chkArg0(CMD_COUNT_STR))
  676.     {
  677.         DLNODE *docNode = dll_first(project->documents);
  678.  
  679.         while (docNode)
  680.         {
  681.             HSCDOC *document = (HSCDOC *) dln_data(docNode);
  682.  
  683.             printf("%s\n", document->docname);
  684.             docNode = dln_next(docNode);
  685.         }
  686.     }
  687. }
  688.  
  689. /*-------------------------------------------------------------------*/
  690.  
  691. /*
  692.  * process_command
  693.  *
  694.  */
  695. BOOL process_command(HSCPRJ * project, LONG command, DLLIST * arglist)
  696. {
  697.     BOOL ok = TRUE;
  698.     DLNODE *nd = NULL;
  699.  
  700.     D(fprintf(stderr, DHP "process_command()\n"));
  701.     D(fprintf(stderr, DHP "command: %s\n", command_name[command]));
  702.  
  703.     /* count number of args */
  704.     if (arglist)
  705.         nd = dll_first(arglist);
  706.     if (nd)
  707.     {
  708.         D(fprintf(stderr, DHP "command args:\n"));
  709.         while (nd)
  710.         {
  711.             D(fprintf(stderr, DHP "  `%s'\n", (STRPTR) dln_data(nd)));
  712.             cmdArgNum++;
  713.             nd = dln_next(nd);
  714.         }
  715.     }
  716.     else
  717.     {
  718.         fprintf(stderr, DHP "command args: NONE\n");
  719.     }
  720.     D(fprintf(stderr, DHP "cmdarg#: %ld\n", cmdArgNum));
  721.  
  722.     switch (command)
  723.     {
  724.     case COMMAND_COUNT:
  725.         command_count(project, arglist);
  726.         break;
  727.     case COMMAND_LIST:
  728.         command_list(project, arglist);
  729.         break;
  730.     case COMMAND_EXTRACT:
  731.         command_extract(project, arglist);
  732.         break;
  733.     case COMMAND_DELETE:
  734.         command_delete(project, arglist);
  735.         break;
  736.     case COMMAND_ERASE:
  737.         command_erase(project, arglist);
  738.         break;
  739.     default:
  740.         {
  741.             D(fprintf(stderr, DHP "unknown command\n"));
  742.             ok = FALSE;
  743.             break;
  744.         }
  745.     }
  746.  
  747.     return (ok);
  748. }
  749.  
  750. /*-------------------------------------------------------------------
  751.  *
  752.  * main function
  753.  *
  754.  *-------------------------------------------------------------------*/
  755. int main(int argc, char *argv[])
  756. {
  757. #ifndef BETA
  758. #define BETA 0
  759. #endif
  760.     /* set program information */
  761.     set_prginfo("hscpitt", "Tommy-Saftwörx", VERSION, REVISION, BETA,
  762.                 "hsc project interfering'n'trashing tool",
  763.                 "Freeware, type `hscpitt LICENSE' for details.");
  764.  
  765. #if DEBUG
  766.     /* display a memory tracking report */
  767.     /* at end of execution */
  768.     atexit(atexit_uglymemory);
  769. #endif
  770.  
  771.     /* install nomem-handler */
  772.     ugly_nomem_handler = hscpitt_nomem_handler;
  773.  
  774.     /* use cleanup() as additional exit func */
  775.     if (!atexit(cleanup))
  776.     {
  777.         /*
  778.          * main procedure
  779.          */
  780.         return_code = RC_OK;
  781.         project = new_project();
  782.         if (project
  783.             && args_ok(argc, argv)
  784.             && read_project()
  785.             && process_command(project, command, command_arglist)
  786.             )
  787.         {
  788.             return_code = RC_OK;
  789.         }
  790.     }
  791.     else
  792.     {
  793.         fputs(SHIT "atexit() failed ", stderr);
  794.     }
  795.     return (return_code);
  796. }
  797.  
  798.